import random
import time

import numpy as np
from ortools.sat.python import cp_model


def get_re_t(solution_x_total, solution_bool_sub_job, solution_bool_C, t):
    '''
    该函数用于得到时间t后还有多少货物没有被处理，以及有多少货物正在被处理
    :param solution_x_total: 所有子任务的开始处理时间和处理结束时间，单位为分钟
    :param solution_bool_sub_job: 该项对应某一个子任务是否被处理，若为1则被处理，若为0则没被处理
    :param solution_bool_C: 该项对应子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用
    :param t: 开始插入的时间
    :return:ini_solution_x_total：子任务的开始处理时间和处理结束时间，单位为分钟（时间t后）
    ini_solution_bool_sub_job：该项对应某一个子任务是否被处理，若为1则被处理，若为0则没被处理（时间t后）
    ini_solution_bool_C：该项对应子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用（时间t后）
    ini_job_re：用于记录被处理的货物编号
    under_process：被记录的货物是否属于正在被处理，1不是，0是
    '''
    ini_solution_x_total = []
    ini_solution_bool_sub_job = []
    ini_solution_bool_C = []
    ini_job_re = []
    under_process = []
    for i in range(len(solution_x_total)):
        ini_sub_solution_x_total = []
        ini_sub_solution_bool_sub_job = []
        ini_sub_solution_bool_C = []
        ini_sub_job_re = []
        ini_under_process = []

        for j in range(len(solution_x_total[i])):

            if solution_x_total[i][j][0] <= t and solution_x_total[i][j][1] > t and solution_bool_sub_job[i][j] == 1:
                ini_sub_solution_x_total.append([t, solution_x_total[i][j][1]])
                ini_sub_solution_bool_sub_job.append(solution_bool_sub_job[i][j])
                ini_sub_solution_bool_C.append(solution_bool_C[i][j])
                ini_sub_job_re.append([i, j])
                ini_under_process.append(0)

            if solution_x_total[i][j][0] > t and solution_bool_sub_job[i][j] == 1:
                ini_sub_solution_x_total.append([solution_x_total[i][j][0], solution_x_total[i][j][1]])
                ini_sub_solution_bool_sub_job.append(solution_bool_sub_job[i][j])
                ini_sub_solution_bool_C.append(solution_bool_C[i][j])
                ini_sub_job_re.append([i, j])
                ini_under_process.append(1)

        if bool(ini_sub_solution_x_total):
            ini_solution_x_total.append(ini_sub_solution_x_total)
            ini_solution_bool_sub_job.append(ini_sub_solution_bool_sub_job)
            ini_solution_bool_C.append(ini_sub_solution_bool_C)
            ini_job_re.append(ini_sub_job_re)
            under_process.append(ini_under_process)

    return ini_solution_x_total, ini_solution_bool_sub_job, ini_solution_bool_C, ini_job_re, under_process


def insert_se_solve(job_data_se, d_list_se, t, ini_s, ini_solution_x_total, ini_job_re, under_process, V_j, s_t):
    '''
    该函数用于处理自制插入货物
    :param job_data_se: 自制任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量
    :param d_list_se: 各个自制货物的截止日期
    :param t: 开始插入的时间
    :param ini_s: 用于区分原始EMS和自制货物的位置
    :param ini_solution_x_total: 所有原始子任务的开始处理时间和处理结束时间，单位为分钟（时间t后）
    :param ini_job_re: 存储着时间窗t之后的货物的下标
    :param under_process: 存储着货物是否属于正在被处理，1不是，0是，对应ini_solution_x_total
    :param V_j: 不同类型货物对应通道的速度，数量/分钟，0的位置对应栈板，1的位置对应件箱，2的位置对应自制
    :param s_t: 求解时间，若最后无解，则需调大时间
    :return: solution_x_total 所有子任务的开始处理时间和处理结束时间，单位为分钟（只包含插入的自制货物）
    solution_bool_sub_job 该项对应某一个子任务是否被处理，若为1则被处理，若为0则没被处理（只包含插入的自制货物）
    solution_bool_C 该项对应子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用（只包含插入的自制货物）
    '''
    # V_j = [2, 17, 3]
    t_t_list = [i * 2 * 60 for i in range(1, 13)]
    total_C_list = []
    total_C_se_list = []
    bool_job_list = []
    bool_job_se_list = []
    bool_sub_job_list = []
    bool_sub_job_se_list = []
    job_p_list = []
    job_p_se_list = []
    x_intervals = []
    y_intervals = []
    solution_x_total = []
    solution_bool_sub_job = []
    solution_bool_C = []
    de = []
    total_b = 0
    total_bb = 0
    model = cp_model.CpModel()
    max_time = cp_model.INT32_MAX

    for i in range(len(ini_solution_x_total)):
        for j in range(len(ini_solution_x_total[i])):
            x_s = model.NewConstant(ini_solution_x_total[i][j][0])
            ii = model.NewConstant(ini_solution_x_total[i][j][1] - ini_solution_x_total[i][j][0])
            x_e = model.NewConstant(ini_solution_x_total[i][j][1])
            if ini_job_re[i][j][0] >= ini_s and under_process[i][j] == 1:
                x_s = model.NewConstant(ini_solution_x_total[i][j][0])
                ii = model.NewConstant(ini_solution_x_total[i][j][1] - ini_solution_x_total[i][j][0])
                x_e = model.NewConstant(ini_solution_x_total[i][j][1])
                y_s = model.NewConstant(7)
                iii = model.NewConstant(1)
                y_e = model.NewConstant(8)
                x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)
                y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)
                de.append(int(3))
                x_intervals.append(x_ii)
                y_intervals.append(y_ii)

    for i in range(len(job_data_se)):
        j_b_se = model.NewBoolVar('%d' % i)
        total_bb += j_b_se
        bool_job_se_list.append(j_b_se)
        job_p_se_sub = []
        C_se_list = []
        bool_sub_job_se = []
        for j in range(len(job_data_se[i])):
            j_sub_b_se = model.NewBoolVar('%d_%d' % (i, j))
            bool_sub_job_se.append(j_sub_b_se)
            total_b += j_sub_b_se
            sub_c_se_list = []
            sub_p_se_list = []
            j_sub_p_se_s = model.NewIntVar(t, 1441, 'p_s_%d_%d' % (i, j))
            j_sub_p_se_e = model.NewIntVar(t, 1441, 'p_e_%d_%d' % (i, j))
            j_sub_p_e_se_1 = model.NewIntVar(t, 1441, 'p_e1_%d_%d' % (i, j))
            due_data_se_d = model.NewBoolVar('due_data_d')
            c_se_d = model.NewBoolVar('c_d')
            model.Add(j_sub_p_se_e <= d_list_se[i]).OnlyEnforceIf(due_data_se_d)
            model.Add(j_sub_p_se_e > d_list_se[i]).OnlyEnforceIf(due_data_se_d.Not())
            sub_p_se_list.append(j_sub_p_se_s)
            sub_p_se_list.append(j_sub_p_se_e)
            sub_p_se_list.append(j_sub_p_e_se_1)
            job_p_se_sub.append(sub_p_se_list)
            b = model.NewBoolVar('%d_%d_%d' % (i, j, 8))
            sub_c_se_list.append(b)

            model.Add(sum(sub_c_se_list) > 0).OnlyEnforceIf(c_se_d)
            model.Add(sum(sub_c_se_list) == 0).OnlyEnforceIf(c_se_d.Not())
            model.Add(due_data_se_d == 1).OnlyEnforceIf(c_se_d)
            model.Add(c_se_d + due_data_se_d == 2).OnlyEnforceIf(j_sub_b_se)
            model.Add(c_se_d + due_data_se_d < 2).OnlyEnforceIf(j_sub_b_se.Not())
            C_se_list.append(sub_c_se_list)
        model.Add(sum(bool_sub_job_se) == len(bool_sub_job_se)).OnlyEnforceIf(j_b_se)
        model.Add(sum(bool_sub_job_se) < len(bool_sub_job_se)).OnlyEnforceIf(j_b_se.Not())
        total_C_se_list.append(C_se_list)
        bool_sub_job_se_list.append(bool_sub_job_se)
        job_p_se_list.append(job_p_se_sub)

    for i in range(len(job_data_se)):
        total_interval_se = 0
        x_t_intervals_se = []
        for j in range(len(job_data_se[i])):
            for k in range(len(total_C_se_list[i][j])):
                total_interval_se += total_C_se_list[i][j][k] * V_j[2]
            t_ii = model.NewIntVar(1, 999999, 't_ii_%d' % j)
            model.Add(t_ii == total_interval_se + 1)
            I_se = model.NewIntVar(0, 999999, 'In_%d' % j)
            model.AddDivisionEquality(I_se, job_data_se[i][j], t_ii)
            j_sub_p_I_se_intervals = model.NewOptionalIntervalVar(job_p_se_list[i][j][0], I_se + 30,
                                                                  job_p_se_list[i][j][2], bool_sub_job_se_list[i][j],
                                                                  '%d_%d_I' % (i, j))
            x_t_intervals_se.append(j_sub_p_I_se_intervals)
            de.append(int(3))
            y_end = model.NewIntVar(0, 9, 'y_end_%d%d%d' % (i, j, 8))
            j_sub_p_se_intervals = model.NewOptionalIntervalVar(job_p_se_list[i][j][0], I_se + 1,
                                                                job_p_se_list[i][j][1], total_C_se_list[i][j][0],
                                                                'p_%d_%d' % (i, j))
            j_sub_c_se_intervals = model.NewOptionalIntervalVar(7, 1, y_end, total_C_se_list[i][j][0],
                                                                'c_%d_%d' % (i, j))
            x_intervals.append(j_sub_p_se_intervals)
            y_intervals.append(j_sub_c_se_intervals)

        model.AddNoOverlap(x_t_intervals_se)
    model.AddNoOverlap2D(x_intervals, y_intervals)

    model.Maximize(total_bb)
    solver = cp_model.CpSolver()
    solver.parameters.num_search_workers = 8
    solver.parameters.max_time_in_seconds = s_t
    # solver.parameters.log_search_progress = True
    status = solver.Solve(model)

    if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
        print("status: ", status)

        for i in range(len(job_data_se)):
            solu_x_sub_se = []
            for j in range(len(job_data_se[i])):
                solution_x_se = []
                solution_x_se.append(solver.Value(job_p_se_list[i][j][0]))
                solution_x_se.append(solver.Value(job_p_se_list[i][j][1]))
                solu_x_sub_se.append(solution_x_se)
            solution_x_total.append(solu_x_sub_se)

        for i in range(len(job_data_se)):
            solu_bool_sub_se = []
            for j in range(len(job_data_se[i])):
                solu_bool_sub_se.append(solver.Value(bool_sub_job_se_list[i][j]))
            solution_bool_sub_job.append(solu_bool_sub_se)

        for i in range(len(job_data_se)):
            solu_C_se_sub = []
            for j in range(len(job_data_se[i])):
                solu_C_sub_sub_se = []
                for k in range(len(total_C_se_list[i][j])):
                    solu_C_sub_sub_se.append(solver.Value(total_C_se_list[i][j][k]))
                solu_C_se_sub.append(solu_C_sub_sub_se)
            solution_bool_C.append(solu_C_se_sub)

        print("youjie")
    else:
        print('No solution found.')

    return solution_x_total, solution_bool_sub_job, solution_bool_C


def insert_re_fun(under_process, in_job, in_job_type, in_d_list, job_type, ini_job_re, ini_s, job_data, d_list,
                  ini_solution_x_total, ss_solution_x_total, ss_solution_bool_sub_job, ss_solution_bool_C, t, V_j, s_t):
    '''
    当在原时间窗上插入无解时，将用此函数进行重排
    :param under_process:存储着货物是否属于正在被处理，1不是，0是，对应ini_solution_x_total, ini_solution_bool_sub_job, ini_solution_bool_C
    :param in_job:插入EMS任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量,同时任务的优先级默认从高到低依次排列
    :param in_job_type:插入EMS货物形态 0可代表栈板，1代表件箱，2代表gtp
    :param in_d_list:插入EMS货物的截止日期
    :param job_type:原始EMS货物形态 0可代表栈板，1代表件箱，2代表gtp
    :param ini_job_re:存储着原始时间窗t之后的货物的下标
    :param ini_s:用于区分原始EMS和自制货物的位置，对应ini_solution_x_total
    :param job_data:原始EMS任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量,同时任务的优先级默认从高到低依次排列
    :param d_list:原始EMS货物的截止日期
    :param ini_solution_x_total:子任务的开始处理时间和处理结束时间，单位为分钟(时间t之后的时间窗货物处理)
    :param ss_solution_x_total:插入自制子任务的开始处理时间和处理结束时间，单位为分钟
    :param ss_solution_bool_sub_job:该项对应某一个插入自制子任务是否被处理，若为1则被处理，若为0则没被处理
    :param ss_solution_bool_C:该项对应插入自制子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用
    :param t:开始插入的时间
    :param V_j: 不同类型货物对应通道的速度，数量/分钟，0的位置对应栈板，1的位置对应件箱，2的位置对应自制
    :param s_t:求解时间，若最后无解，则需调大时间
    :return:s_solution_x_total:子任务的开始处理时间和处理结束时间，单位为分(四部分，插入的EMS部分，插入的自制部分，原有的EMS部分，原有的自制部分)
    s_solution_bool_sub_job:该项对应某一个子任务是否被处理，若为1则被处理，若为0则没被处理(四部分，插入的EMS部分，插入的自制部分，原有的EMS部分，原有的自制部分)
    s_solution_bool_C:该项对应子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用(四部分，插入的EMS部分，插入的自制部分，原有的EMS部分，原有的自制部分)
    '''
    total_bb = 0
    bool_job_list = []
    ini_bool_job_list = []
    total_b = 0
    # V_j = [2, 17, 3]
    ini_data = []
    ini_d_list = []
    ini_job_type = []
    x_intervals = []
    y_intervals = []
    rs_c = []
    de = []
    total_C_list = []
    bool_sub_job_list = []
    job_p_list = []
    bool_job_se_list = []
    total_C_se_list = []
    bool_sub_job_se_list = []
    job_p_se_list = []
    s_total_C_list = []
    s_bool_sub_job_list = []
    s_job_p_list = []
    i_solution_x_total = []
    i_solution_bool_sub_job = []
    i_solution_bool_C = []
    re_ini_solution_x_total = []
    re_ini_solution_bool_sub_job = []
    re_ini_solution_bool_C = []
    s_solution_x_total = []
    s_solution_bool_sub_job = []
    s_solution_bool_C = []
    se_solution_x_total = []
    se_solution_bool_sub_job = []
    se_solution_bool_C = []

    model = cp_model.CpModel()
    max_time = cp_model.INT32_MAX

    for i in range(len(ini_solution_x_total)):
        se_sub_solution_x_total = []
        se_sub_solution_bool_sub_job = []
        se_sub_solution_bool_C = []
        for j in range(len(ini_solution_x_total[i])):
            x_s = model.NewConstant(ini_solution_x_total[i][j][0])
            ii = model.NewConstant(ini_solution_x_total[i][j][1] - ini_solution_x_total[i][j][0])
            x_e = model.NewConstant(ini_solution_x_total[i][j][1])
            if ini_job_re[i][j][0] >= ini_s and under_process[i][j] == 1:
                se_sub_solution_x_total.append([ini_solution_x_total[i][j][0], ini_solution_x_total[i][j][1]])
                se_sub_solution_bool_sub_job.append(1)
                se_sub_solution_bool_C.append([1])
                y_s = model.NewConstant(7)
                iii = model.NewConstant(1)
                y_e = model.NewConstant(8)
                x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'inin_x_ii%d' % i)
                y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'inin_y_ii%d' % i)
                rs_c.append(x_ii)
                de.append(int(3))
                x_intervals.append(x_ii)
                y_intervals.append(y_ii)
            se_solution_x_total.append(se_sub_solution_x_total)
            se_solution_bool_sub_job.append(se_sub_solution_bool_sub_job)
            se_solution_bool_C.append(se_sub_solution_bool_C)

    if bool(ss_solution_x_total):
        for g in range(len(ss_solution_x_total)):
            for i in range(len(ss_solution_x_total[g])):
                x_s = model.NewConstant(ss_solution_x_total[g][i][0])
                ii = model.NewConstant(ss_solution_x_total[g][i][1] - ss_solution_x_total[g][i][0])
                x_e = model.NewConstant(ss_solution_x_total[g][i][1])
                y_s = model.NewConstant(7)
                iii = model.NewConstant(1)
                y_e = model.NewConstant(8)
                if ss_solution_bool_sub_job[g][i] == 1:
                    x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, ss_solution_bool_sub_job[g][i], 'sss_x_ii%d' % i)
                    y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, ss_solution_bool_sub_job[g][i], 'sss_y_ii%d' % i)
                    x_intervals.append(x_ii)
                    y_intervals.append(y_ii)
                    de.append(int(3))
                    rs_c.append(x_ii)

    for i in range(len(ini_job_re)):
        ini_sub_data = []
        ini_sub_d_list = []
        ini_sub_job_type = []
        for j in range(len(ini_job_re[i])):
            if ini_job_re[i][j][0] < ini_s and under_process[i][j] == 1:
                ini_sub_data.append(job_data[ini_job_re[i][j][0]][ini_job_re[i][j][1]])
                ini_sub_d_list.append(d_list[ini_job_re[i][j][0]])
                ini_sub_job_type.append(job_type[ini_job_re[i][j][0]][ini_job_re[i][j][1]])
        ini_data.append(ini_sub_data)
        ini_d_list.append(ini_sub_d_list)
        ini_job_type.append(ini_sub_job_type)

    for i in range(len(ini_data)):
        j_b = model.NewBoolVar('ini_%d' % i)
        total_bb += j_b
        ini_bool_job_list.append(j_b)
        job_p_sub = []
        C_list = []
        bool_sub_job = []
        for j in range(len(ini_data[i])):
            j_sub_b = model.NewBoolVar('ini_%d_%d' % (i, j))
            bool_sub_job.append(j_sub_b)
            total_b += j_sub_b
            sub_c_list = []
            sub_p_list = []
            j_sub_p_s = model.NewIntVar(t, 1441, 'ini_p_s_%d_%d' % (i, j))
            j_sub_p_e = model.NewIntVar(t, 1441, 'ini_p_e_%d_%d' % (i, j))
            j_sub_p_e_1 = model.NewIntVar(t, 1441, 'ini_p_e1_%d_%d' % (i, j))
            due_data_d = model.NewBoolVar('ini_due_data_d')
            c_d = model.NewBoolVar('ini_c_d')
            model.Add(j_sub_p_e <= ini_d_list[i][j]).OnlyEnforceIf(due_data_d)
            model.Add(j_sub_p_e > ini_d_list[i][j]).OnlyEnforceIf(due_data_d.Not())
            sub_p_list.append(j_sub_p_s)
            sub_p_list.append(j_sub_p_e)
            sub_p_list.append(j_sub_p_e_1)
            job_p_sub.append(sub_p_list)
            if ini_job_type[i][j] == 0:
                b = model.NewBoolVar('ini_%d_%d_%d' % (i, j, 7))
                sub_c_list.append(b)
            else:
                for m in range(6):
                    b = model.NewBoolVar('ini_%d_%d_%d' % (i, j, m))
                    sub_c_list.append(b)

            model.Add(sum(sub_c_list) > 0).OnlyEnforceIf(c_d)
            model.Add(sum(sub_c_list) == 0).OnlyEnforceIf(c_d.Not())
            model.Add(due_data_d == 1).OnlyEnforceIf(c_d)
            model.Add(c_d + due_data_d == 2).OnlyEnforceIf(j_sub_b)
            model.Add(c_d + due_data_d < 2).OnlyEnforceIf(j_sub_b.Not())
            C_list.append(sub_c_list)
        model.Add(sum(bool_sub_job) == len(bool_sub_job)).OnlyEnforceIf(j_b)
        model.Add(sum(bool_sub_job) < len(bool_sub_job)).OnlyEnforceIf(j_b.Not())
        total_C_list.append(C_list)
        bool_sub_job_list.append(bool_sub_job)
        job_p_list.append(job_p_sub)

    for i in range(len(ini_data)):
        total_interval = 0
        x_t_intervals = []
        for j in range(len(ini_data[i])):
            for k in range(len(total_C_list[i][j])):
                total_interval += total_C_list[i][j][k] * V_j[ini_job_type[i][j]]
            t_i = model.NewIntVar(1, 999999, 'i_i_%d' % j)
            model.Add(t_i == total_interval + 1)
            I = model.NewIntVar(0, 999999, 'ini_%d' % j)
            model.AddDivisionEquality(I, ini_data[i][j], t_i)
            j_sub_p_I_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][0], I + 30, job_p_list[i][j][2],
                                                               bool_sub_job_list[i][j], '%d_%d_Ini' % (i, j))
            x_t_intervals.append(j_sub_p_I_intervals)
            for m in range(len(total_C_list[i][j])):
                # de.append(int(17))
                y_end = model.NewIntVar(1, 6, 'ini_y_end_%d%d%d' % (i, j, m))
                j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][0], I + 1, job_p_list[i][j][1],
                                                                 total_C_list[i][j][m], 'ini_p_%d_%d' % (i, j))
                j_sub_c_intervals = model.NewOptionalIntervalVar(m, 1, y_end, total_C_list[i][j][m],
                                                                 'ini_c_%d_%d' % (i, j))
                if ini_job_type[i][j] == 1:
                    rs_c.append(j_sub_p_intervals)
                    de.append(int(17))
                x_intervals.append(j_sub_p_intervals)
                y_intervals.append(j_sub_c_intervals)

        model.AddNoOverlap(x_t_intervals)

    for i in range(len(in_job)):
        j_b = model.NewBoolVar('%d' % i)
        total_bb += j_b
        bool_job_list.append(j_b)
        job_p_sub = []
        C_list = []
        bool_sub_job = []
        for j in range(len(in_job[i])):
            j_sub_b = model.NewBoolVar('%d_%d' % (i, j))
            bool_sub_job.append(j_sub_b)
            total_b += j_sub_b
            sub_c_list = []
            sub_p_list = []
            j_sub_p_s = model.NewIntVar(0, 1441, 'p_s_%d_%d' % (i, j))
            j_sub_p_e = model.NewIntVar(0, 1441, 'p_e_%d_%d' % (i, j))
            j_sub_p_e_1 = model.NewIntVar(0, 1441, 'p_e1_%d_%d' % (i, j))
            due_data_d = model.NewBoolVar('due_data_d')
            c_d = model.NewBoolVar('c_d')
            model.Add(j_sub_p_e <= in_d_list[i]).OnlyEnforceIf(due_data_d)
            model.Add(j_sub_p_e > in_d_list[i]).OnlyEnforceIf(due_data_d.Not())
            sub_p_list.append(j_sub_p_s)
            sub_p_list.append(j_sub_p_e)
            sub_p_list.append(j_sub_p_e_1)
            job_p_sub.append(sub_p_list)
            if in_job_type[i][j] == 0:
                b = model.NewBoolVar('%d_%d_%d' % (i, j, 7))
                sub_c_list.append(b)
            else:
                for m in range(6):
                    b = model.NewBoolVar('%d_%d_%d' % (i, j, m))
                    sub_c_list.append(b)

            model.Add(sum(sub_c_list) > 0).OnlyEnforceIf(c_d)
            model.Add(sum(sub_c_list) == 0).OnlyEnforceIf(c_d.Not())
            model.Add(due_data_d == 1).OnlyEnforceIf(c_d)
            model.Add(c_d + due_data_d == 2).OnlyEnforceIf(j_sub_b)
            model.Add(c_d + due_data_d < 2).OnlyEnforceIf(j_sub_b.Not())
            C_list.append(sub_c_list)
        model.Add(sum(bool_sub_job) == len(bool_sub_job)).OnlyEnforceIf(j_b)
        model.Add(sum(bool_sub_job) < len(bool_sub_job)).OnlyEnforceIf(j_b.Not())
        s_total_C_list.append(C_list)
        s_bool_sub_job_list.append(bool_sub_job)
        s_job_p_list.append(job_p_sub)

    for i in range(len(in_job)):
        total_interval = 0
        x_t_intervals = []
        for j in range(len(in_job[i])):
            for k in range(len(s_total_C_list[i][j])):
                total_interval += s_total_C_list[i][j][k] * V_j[in_job_type[i][j]]
            t_i = model.NewIntVar(1, 999999, 't_i_%d' % j)
            model.Add(t_i == total_interval + 1)
            I = model.NewIntVar(0, 999999, 'In_%d' % j)
            model.AddDivisionEquality(I, in_job[i][j], t_i)
            j_sub_p_I_intervals = model.NewOptionalIntervalVar(s_job_p_list[i][j][0], I + 30, s_job_p_list[i][j][2],
                                                               s_bool_sub_job_list[i][j], '%d_%d_I' % (i, j))
            x_t_intervals.append(j_sub_p_I_intervals)
            for m in range(len(s_total_C_list[i][j])):
                # de.append(int(17))
                y_end = model.NewIntVar(1, 6, 'y_end_%d%d%d' % (i, j, m))
                j_sub_p_intervals = model.NewOptionalIntervalVar(s_job_p_list[i][j][0], I + 1, s_job_p_list[i][j][1],
                                                                 s_total_C_list[i][j][m], 'p_%d_%d' % (i, j))
                j_sub_c_intervals = model.NewOptionalIntervalVar(m, 1, y_end, s_total_C_list[i][j][m],
                                                                 'c_%d_%d' % (i, j))
                if in_job_type[i][j] == 1:
                    rs_c.append(j_sub_p_intervals)
                    de.append(int(17))
                x_intervals.append(j_sub_p_intervals)
                y_intervals.append(j_sub_c_intervals)

        model.AddNoOverlap(x_t_intervals)

    end_bool_job_list = bool_job_list + ini_bool_job_list
    for i in range(len(end_bool_job_list) - 1):
        model.Add(end_bool_job_list[i] == 1).OnlyEnforceIf(end_bool_job_list[i + 1])

    model.AddNoOverlap2D(x_intervals, y_intervals)
    model.AddCumulative(rs_c, de, 84)

    model.Maximize(total_bb)
    solver = cp_model.CpSolver()
    solver.parameters.num_search_workers = 8
    solver.parameters.max_time_in_seconds = s_t
    # solver.parameters.log_search_progress = True
    status = solver.Solve(model)

    if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
        print("status: ", status)
        for i in range(len(in_job)):
            solu_x_sub = []
            for j in range(len(in_job[i])):
                solution_x = []
                solution_x.append(solver.Value(s_job_p_list[i][j][0]))
                solution_x.append(solver.Value(s_job_p_list[i][j][1]))
                solu_x_sub.append(solution_x)
            i_solution_x_total.append(solu_x_sub)

        for i in range(len(ini_data)):
            solu_x_sub = []
            for j in range(len(ini_data[i])):
                solution_x = []
                solution_x.append(solver.Value(job_p_list[i][j][0]))
                solution_x.append(solver.Value(job_p_list[i][j][1]))
                solu_x_sub.append(solution_x)
            re_ini_solution_x_total.append(solu_x_sub)

        s_solution_x_total = i_solution_x_total + ss_solution_x_total + re_ini_solution_x_total + se_solution_x_total

        for i in range(len(in_job)):
            solu_bool_sub = []
            for j in range(len(in_job[i])):
                solu_bool_sub.append(solver.Value(s_bool_sub_job_list[i][j]))
            i_solution_bool_sub_job.append(solu_bool_sub)

        for i in range(len(ini_data)):
            solu_bool_sub = []
            for j in range(len(ini_data[i])):
                solu_bool_sub.append(solver.Value(bool_sub_job_list[i][j]))
            re_ini_solution_bool_sub_job.append(solu_bool_sub)

        s_solution_bool_sub_job = i_solution_bool_sub_job + ss_solution_bool_sub_job + re_ini_solution_bool_sub_job + se_solution_bool_sub_job

        for i in range(len(in_job)):
            solu_C_sub = []
            for j in range(len(in_job[i])):
                solu_C_sub_sub = []
                for k in range(len(s_total_C_list[i][j])):
                    solu_C_sub_sub.append(solver.Value(s_total_C_list[i][j][k]))
                solu_C_sub.append(solu_C_sub_sub)
            i_solution_bool_C.append(solu_C_sub)

        for i in range(len(ini_data)):
            solu_C_sub = []
            for j in range(len(ini_data[i])):
                solu_C_sub_sub = []
                for k in range(len(total_C_list[i][j])):
                    solu_C_sub_sub.append(solver.Value(total_C_list[i][j][k]))
                solu_C_sub.append(solu_C_sub_sub)
            re_ini_solution_bool_C.append(solu_C_sub)

        s_solution_bool_C = i_solution_bool_C + ss_solution_bool_C + re_ini_solution_bool_C + se_solution_bool_C

        print("youjie")

        # return s_solution_x_total, s_solution_bool_sub_job, s_solution_bool_C
    else:
        print('No solution found.')

    return s_solution_x_total, s_solution_bool_sub_job, s_solution_bool_C


def insert_fun(in_job, in_job_type, in_job_se, in_d_list_se, ini_s, solution_x_total, solution_bool_sub_job,
               solution_bool_C, t, in_d_list, d_list, job_type, job_data, V_j, s_t):
    '''
    该函数用于求解插入货物后的时间窗
    :param in_job: 任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量,同时任务的优先级默认从高到低依次排列
    :param in_job_type: EMS货物形态 0可代表栈板，1代表件箱，2代表gtp
    :param in_job_se: 任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量
    :param in_d_list_se: 各个自制货物的截止日期
    :param ini_s: 用于区分原始EMS和自制货物的位置
    :param solution_x_total: 所有子任务的开始处理时间和处理结束时间，单位为分钟
    :param solution_bool_sub_job: 该项对应某一个子任务是否被处理，若为1则被处理，若为0则没被处理
    :param solution_bool_C: 该项对应子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用
    :param t: 开始插入的时间
    :param in_d_list: EMS货物的截止日期
    :param d_list: EMS货物的截止日期
    :param job_type: EMS货物形态 0可代表栈板，1代表件箱，2代表gtp
    :param job_data: EMS任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量,同时任务的优先级默认从高到低依次排列
    :param V_j: 不同类型货物对应通道的速度，数量/分钟，0的位置对应栈板，1的位置对应件箱，2的位置对应自制
    :param s_t: 求解时间，若最后无解，则需调大时间
    :return: s_solution_x_total, s_solution_bool_sub_job, s_solution_bool_C(插入成功：三部分，插入的EMS部分，插入的自制部分，原有的时间窗部分。插入失败需重排：四部分，插入的EMS部分，插入的自制部分，原有的EMS部分，原有的自制部分)
    '''
    total_bb = 0
    total_b = 0
    # V_j = [2, 17, 3]
    # bool_job_se_list = []
    # total_C_se_list = []
    # bool_sub_job_se_list = []
    # job_p_se_list = []
    i_solution_x_total = []
    i_solution_bool_sub_job = []
    i_solution_bool_C = []
    # i_se_solution_x_total = []
    # i_se_solution_bool_sub_job = []
    # i_se_solution_bool_C = []

    rs_c = []
    de = []
    bool_job_list = []
    s_total_C_list = []
    s_bool_sub_job_list = []
    s_job_p_list = []
    x_intervals = []
    y_intervals = []
    ini_solution_x_total, ini_solution_bool_sub_job, ini_solution_bool_C, ini_job_re, under_process = get_re_t(
        solution_x_total, solution_bool_sub_job, solution_bool_C, t)
    if bool(in_job_se):
        ss_solution_x_total, ss_solution_bool_sub_job, ss_solution_bool_C = insert_se_solve(in_job_se, in_d_list_se, t,
                                                                                            ini_s, ini_solution_x_total,
                                                                                            ini_job_re, under_process,
                                                                                            V_j, s_t)
    else:
        ss_solution_x_total, ss_solution_bool_sub_job, ss_solution_bool_C = [], [], []
    model = cp_model.CpModel()
    max_time = cp_model.INT32_MAX

    for i in range(len(ini_solution_x_total)):
        for j in range(len(ini_solution_x_total[i])):
            for k in range(len(ini_solution_bool_C[i][j])):
                x_s = model.NewConstant(ini_solution_x_total[i][j][0])
                ii = model.NewConstant(ini_solution_x_total[i][j][1] - ini_solution_x_total[i][j][0])
                x_e = model.NewConstant(ini_solution_x_total[i][j][1])
                if ini_job_re[i][j][0] < ini_s:
                    if len(ini_solution_bool_C[i][j]) == 1:
                        y_s = model.NewConstant(6)
                        iii = model.NewConstant(1)
                        y_e = model.NewConstant(7)
                        x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)
                        y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)
                        x_intervals.append(x_ii)
                        y_intervals.append(y_ii)
                    else:
                        y_s = model.NewConstant(k)
                        iii = model.NewConstant(1)
                        y_e = model.NewConstant(k + 1)
                        x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)
                        y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)
                        rs_c.append(x_ii)
                        de.append(int(17))
                        x_intervals.append(x_ii)
                        y_intervals.append(y_ii)

                else:
                    y_s = model.NewConstant(7)
                    iii = model.NewConstant(1)
                    y_e = model.NewConstant(8)
                    x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)
                    y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)
                    rs_c.append(x_ii)
                    de.append(int(3))
                    x_intervals.append(x_ii)
                    y_intervals.append(y_ii)

                # x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)  # y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)  # x_intervals.append(x_ii)  # y_intervals.append(y_ii)
    if bool(in_job_se):
        for g in range(len(ss_solution_x_total)):
            for i in range(len(ss_solution_x_total[g])):
                x_s = model.NewConstant(ss_solution_x_total[g][i][0])
                ii = model.NewConstant(ss_solution_x_total[g][i][1] - ss_solution_x_total[g][i][0])
                x_e = model.NewConstant(ss_solution_x_total[g][i][1])
                y_s = model.NewConstant(7)
                iii = model.NewConstant(1)
                y_e = model.NewConstant(8)
                if ss_solution_bool_sub_job[g][i] == 1:
                    x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, ss_solution_bool_sub_job[g][i], 'x_ii%d' % i)
                    y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, ss_solution_bool_sub_job[g][i], 'y_ii%d' % i)
                    x_intervals.append(x_ii)
                    y_intervals.append(y_ii)
                    de.append(int(3))
                    rs_c.append(x_ii)

    for i in range(len(in_job)):
        j_b = model.NewBoolVar('%d' % i)
        total_bb += j_b
        bool_job_list.append(j_b)
        job_p_sub = []
        C_list = []
        bool_sub_job = []
        for j in range(len(in_job[i])):
            j_sub_b = model.NewBoolVar('%d_%d' % (i, j))
            bool_sub_job.append(j_sub_b)
            total_b += j_sub_b
            sub_c_list = []
            sub_p_list = []
            j_sub_p_s = model.NewIntVar(t, 1441, 'p_s_%d_%d' % (i, j))
            j_sub_p_e = model.NewIntVar(t, 1441, 'p_e_%d_%d' % (i, j))
            j_sub_p_e_1 = model.NewIntVar(t, 1441, 'p_e1_%d_%d' % (i, j))
            due_data_d = model.NewBoolVar('due_data_d')
            c_d = model.NewBoolVar('c_d')
            model.Add(j_sub_p_e <= in_d_list[i]).OnlyEnforceIf(due_data_d)
            model.Add(j_sub_p_e > in_d_list[i]).OnlyEnforceIf(due_data_d.Not())
            sub_p_list.append(j_sub_p_s)
            sub_p_list.append(j_sub_p_e)
            sub_p_list.append(j_sub_p_e_1)
            job_p_sub.append(sub_p_list)
            # if se[i]:
            #     for m in range(7):
            #         b = model.NewBoolVar('%d_%d_%d' % (i, j, m))
            #         sub_c_list.append(b)
            # else:
            if in_job_type[i][j] == 0:
                b = model.NewBoolVar('%d_%d_%d' % (i, j, 7))
                sub_c_list.append(b)
            else:
                for m in range(6):
                    b = model.NewBoolVar('%d_%d_%d' % (i, j, m))
                    sub_c_list.append(b)

            model.Add(sum(sub_c_list) > 0).OnlyEnforceIf(c_d)
            model.Add(sum(sub_c_list) == 0).OnlyEnforceIf(c_d.Not())
            model.Add(due_data_d == 1).OnlyEnforceIf(c_d)
            model.Add(c_d + due_data_d == 2).OnlyEnforceIf(j_sub_b)
            model.Add(c_d + due_data_d < 2).OnlyEnforceIf(j_sub_b.Not())
            C_list.append(sub_c_list)
        model.Add(sum(bool_sub_job) == len(bool_sub_job)).OnlyEnforceIf(j_b)
        model.Add(sum(bool_sub_job) < len(bool_sub_job)).OnlyEnforceIf(j_b.Not())
        s_total_C_list.append(C_list)
        s_bool_sub_job_list.append(bool_sub_job)
        s_job_p_list.append(job_p_sub)

    for i in range(len(in_job)):
        total_interval = 0
        x_t_intervals = []
        for j in range(len(in_job[i])):
            for k in range(len(s_total_C_list[i][j])):
                total_interval += s_total_C_list[i][j][k] * V_j[in_job_type[i][j]]
            t_i = model.NewIntVar(1, 999999, 't_i_%d' % j)
            model.Add(t_i == total_interval + 1)
            I = model.NewIntVar(0, 999999, 'In_%d' % j)
            model.AddDivisionEquality(I, in_job[i][j], t_i)
            j_sub_p_I_intervals = model.NewOptionalIntervalVar(s_job_p_list[i][j][0], I + 30, s_job_p_list[i][j][2],
                                                               s_bool_sub_job_list[i][j], '%d_%d_I' % (i, j))
            x_t_intervals.append(j_sub_p_I_intervals)
            for m in range(len(s_total_C_list[i][j])):
                # de.append(int(17))
                y_end = model.NewIntVar(1, 6, 'y_end_%d%d%d' % (i, j, m))
                j_sub_p_intervals = model.NewOptionalIntervalVar(s_job_p_list[i][j][0], I + 1, s_job_p_list[i][j][1],
                                                                 s_total_C_list[i][j][m], 'p_%d_%d' % (i, j))
                j_sub_c_intervals = model.NewOptionalIntervalVar(m, 1, y_end, s_total_C_list[i][j][m],
                                                                 'c_%d_%d' % (i, j))
                if in_job_type[i][j] == 1:
                    rs_c.append(j_sub_p_intervals)
                    de.append(int(17))
                x_intervals.append(j_sub_p_intervals)
                y_intervals.append(j_sub_c_intervals)

        model.AddNoOverlap(x_t_intervals)

    model.AddNoOverlap2D(x_intervals, y_intervals)
    model.AddCumulative(rs_c, de, 84)

    model.Maximize(total_bb)
    solver = cp_model.CpSolver()
    solver.parameters.num_search_workers = 8
    solver.parameters.max_time_in_seconds = t
    # solver.parameters.log_search_progress = True
    status = solver.Solve(model)

    if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
        print("status: ", status)
        for i in range(len(in_job)):
            solu_x_sub = []
            for j in range(len(in_job[i])):
                solution_x = []
                solution_x.append(solver.Value(s_job_p_list[i][j][0]))
                solution_x.append(solver.Value(s_job_p_list[i][j][1]))
                solu_x_sub.append(solution_x)
            i_solution_x_total.append(solu_x_sub)

        s_solution_x_total = i_solution_x_total + ss_solution_x_total + ini_solution_x_total

        for i in range(len(in_job)):
            solu_bool_sub = []
            for j in range(len(in_job[i])):
                solu_bool_sub.append(solver.Value(s_bool_sub_job_list[i][j]))
            i_solution_bool_sub_job.append(solu_bool_sub)

        s_solution_bool_sub_job = i_solution_bool_sub_job + ss_solution_bool_sub_job + ini_solution_bool_sub_job

        for i in range(len(in_job)):
            solu_C_sub = []
            for j in range(len(in_job[i])):
                solu_C_sub_sub = []
                for k in range(len(s_total_C_list[i][j])):
                    solu_C_sub_sub.append(solver.Value(s_total_C_list[i][j][k]))
                solu_C_sub.append(solu_C_sub_sub)
            i_solution_bool_C.append(solu_C_sub)

        s_solution_bool_C = i_solution_bool_C + ss_solution_bool_C + ini_solution_bool_C

        print("youjie")
        if sum(list(map(lambda x: len(x), i_solution_bool_sub_job))) == sum(
                list(map(lambda x: sum(x), i_solution_bool_sub_job))):
            return s_solution_x_total, s_solution_bool_sub_job, s_solution_bool_C
        else:
            s_solution_x_total, s_solution_bool_sub_job, s_solution_bool_C = insert_re_fun(under_process, in_job,
                                                                                           in_job_type, in_d_list,
                                                                                           job_type, ini_job_re, ini_s,
                                                                                           job_data, d_list,
                                                                                           ini_solution_x_total,
                                                                                           ss_solution_x_total,
                                                                                           ss_solution_bool_sub_job,
                                                                                           ss_solution_bool_C, t, V_j,
                                                                                           s_t)
            return s_solution_x_total, s_solution_bool_sub_job, s_solution_bool_C
    else:
        print('No solution found.')

    s_solution_x_total, s_solution_bool_sub_job, s_solution_bool_C = insert_re_fun(under_process, in_job, in_job_type,
                                                                                   in_d_list, job_type, ini_job_re,
                                                                                   ini_s, job_data, d_list,
                                                                                   ini_solution_x_total,
                                                                                   ss_solution_x_total,
                                                                                   ss_solution_bool_sub_job,
                                                                                   ss_solution_bool_C, t, V_j, s_t)

    return s_solution_x_total, s_solution_bool_sub_job, s_solution_bool_C


def generate_data(job_num, op_num_low, op_num_high):
    """
    该函数用于生成数据，输入输出参数解释如下
    :param job_num: 任务的数量
    :param op_num_low: 生成子任务数量的下限
    :param op_num_high: 生成子任务数量的上限
    :return: data_end:任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量
    job_type:货物形态
    job_p:任务的优先级
    se:是否为自制
    d_list:任务的截止时间
    """
    # np.random.seed(12)
    # random.seed(12)
    due_data = [18 * 60, 21 * 60, 24 * 60]
    start_se = [8 * 60, 9 * 60, 10 * 60, 11 * 60, 13 * 60, 15 * 60]
    # due_data_se = []
    d = []
    data_end = []
    data_end_se = []
    data_start_se = []
    # due_data = []
    job_type = []
    job_p = []
    se = []
    d_list = []
    d_list_se = []
    n = np.random.randint(job_num // 2 + 1, job_num)

    for i in range(job_num):
        job_list = []
        op_type = []
        # d_list.append(random.sample(due_data, 1)[0])
        op_num = np.random.randint(op_num_low, op_num_high)

        if i <= n:
            for j in range(op_num):
                # num = np.random.randint(num_low, num_high)
                ty = np.random.randint(0, 3)
                if ty == 0:
                    num = np.random.randint(40, 250)
                elif ty == 1:
                    num = np.random.randint(200, 800)
                elif ty == 2:
                    num = np.random.randint(200, 800)
                # s = np.random.randint(0, 2)
                op_type.append(ty)
                job_list.append(num)  # d_list.append(random.sample(due_data, 1))
            data_end.append(job_list)
            d_list.append(random.sample(due_data, 1)[0])
            # d.append(d_list)
            job_type.append(op_type)  # job_p.append(i)
        else:
            for j in range(op_num):
                # num = np.random.randint(num_low, num_high)
                ty = np.random.randint(0, 3)
                if ty == 0:
                    num = np.random.randint(40, 250)
                elif ty == 1:
                    num = np.random.randint(200, 800)
                elif ty == 2:
                    num = np.random.randint(200, 800)
                # s = np.random.randint(0, 2)
                # op_type.append(ty)
                job_list.append(num)  # d_list.append(random.sample(due_data, 1))
            data_end_se.append(job_list)
            d_list_se.append(random.sample(due_data, 1)[0])
            data_start_se.append(
                random.sample(start_se, 1)[0])  # d.append(d_list)  # job_type.append(op_type)  # job_p.append(i)

    return data_end, data_end_se, job_type, d_list, d_list_se, data_start_se


def generate_data_1(job_num, op_num_low, op_num_high):
    """
    该函数用于生成数据，输入输出参数解释如下
    :param job_num: 任务的数量
    :param op_num_low: 生成子任务数量的下限
    :param op_num_high: 生成子任务数量的上限
    :return: data_end:任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量
    job_type:货物形态
    job_p:任务的优先级
    se:是否为自制
    d_list:任务的截止时间
    """
    # np.random.seed(12)
    # random.seed(12)
    due_data = [18 * 60, 21 * 60, 24 * 60]
    start_se = [20 * 60, 24 * 60]
    # due_data_se = []
    d = []
    data_end = []
    data_end_se = []
    data_start_se = []
    # due_data = []
    job_type = []
    job_p = []
    se = []
    d_list = []
    d_list_se = []
    n = np.random.randint(job_num // 2 + 1, job_num)

    for i in range(job_num):
        job_list = []
        op_type = []
        # d_list.append(random.sample(due_data, 1)[0])
        op_num = np.random.randint(op_num_low, op_num_high)

        if i <= n:
            for j in range(op_num):
                # num = np.random.randint(num_low, num_high)
                ty = np.random.randint(0, 3)
                if ty == 0:
                    num = np.random.randint(40, 250)
                elif ty == 1:
                    num = np.random.randint(200, 800)
                elif ty == 2:
                    num = np.random.randint(200, 800)
                # s = np.random.randint(0, 2)
                op_type.append(ty)
                job_list.append(num)  # d_list.append(random.sample(due_data, 1))
            data_end.append(job_list)
            d_list.append(random.sample(due_data, 1)[0])
            # d.append(d_list)
            job_type.append(op_type)  # job_p.append(i)
        else:
            for j in range(op_num):
                # num = np.random.randint(num_low, num_high)
                ty = np.random.randint(0, 3)
                if ty == 0:
                    num = np.random.randint(40, 250)
                elif ty == 1:
                    num = np.random.randint(200, 800)
                elif ty == 2:
                    num = np.random.randint(200, 800)
                # s = np.random.randint(0, 2)
                # op_type.append(ty)
                job_list.append(num)  # d_list.append(random.sample(due_data, 1))
            data_end_se.append(job_list)
            d_list_se.append(random.sample(due_data, 1)[0])
            data_start_se.append(
                random.sample(start_se, 1)[0])  # d.append(d_list)  # job_type.append(op_type)  # job_p.append(i)

    return data_end, data_end_se, job_type, d_list, d_list_se, data_start_se


def se_solve(job_data_se, d_list_se, data_start_se, t):
    V_j = [2, 17, 3]
    t_t_list = [i * 2 * 60 for i in range(5, 13)]
    total_C_list = []
    total_C_se_list = []
    bool_job_list = []
    bool_job_se_list = []
    bool_sub_job_list = []
    bool_sub_job_se_list = []
    job_p_list = []
    job_p_se_list = []
    x_intervals = []
    y_intervals = []
    solution_x_total = []
    solution_bool_sub_job = []
    solution_bool_C = []
    de = []
    total_b = 0
    total_bb = 0
    model = cp_model.CpModel()
    max_time = cp_model.INT32_MAX

    for i in range(len(job_data_se)):
        j_b_se = model.NewBoolVar('%d' % i)
        total_bb += j_b_se
        bool_job_se_list.append(j_b_se)
        job_p_se_sub = []
        C_se_list = []
        bool_sub_job_se = []
        for j in range(len(job_data_se[i])):
            j_sub_b_se = model.NewBoolVar('%d_%d' % (i, j))
            bool_sub_job_se.append(j_sub_b_se)
            total_b += j_sub_b_se
            sub_c_se_list = []
            sub_p_se_list = []
            j_sub_p_se_s = model.NewIntVar(data_start_se[i], 1441, 'p_s_%d_%d' % (i, j))
            j_sub_p_se_e = model.NewIntVar(data_start_se[i], 1441, 'p_e_%d_%d' % (i, j))
            j_sub_p_e_se_1 = model.NewIntVar(data_start_se[i], 1441, 'p_e1_%d_%d' % (i, j))
            due_data_se_d = model.NewBoolVar('due_data_d')
            c_se_d = model.NewBoolVar('c_d')
            model.Add(j_sub_p_se_e <= d_list_se[i]).OnlyEnforceIf(due_data_se_d)
            model.Add(j_sub_p_se_e > d_list_se[i]).OnlyEnforceIf(due_data_se_d.Not())
            sub_p_se_list.append(j_sub_p_se_s)
            sub_p_se_list.append(j_sub_p_se_e)
            sub_p_se_list.append(j_sub_p_e_se_1)
            job_p_se_sub.append(sub_p_se_list)
            b = model.NewBoolVar('%d_%d_%d' % (i, j, 8))
            sub_c_se_list.append(b)
            # if se[i]:
            #     for m in range(7):
            #         b = model.NewBoolVar('%d_%d_%d' % (i, j, m))
            #         sub_c_se_list.append(b)
            # else:
            #     for m in range(6):
            #         b = model.NewBoolVar('%d_%d_%d' % (i, j, m))
            #         sub_c_list.append(b)

            model.Add(sum(sub_c_se_list) > 0).OnlyEnforceIf(c_se_d)
            model.Add(sum(sub_c_se_list) == 0).OnlyEnforceIf(c_se_d.Not())
            model.Add(due_data_se_d == 1).OnlyEnforceIf(c_se_d)
            model.Add(c_se_d + due_data_se_d == 2).OnlyEnforceIf(j_sub_b_se)
            model.Add(c_se_d + due_data_se_d < 2).OnlyEnforceIf(j_sub_b_se.Not())
            C_se_list.append(sub_c_se_list)
        model.Add(sum(bool_sub_job_se) == len(bool_sub_job_se)).OnlyEnforceIf(j_b_se)
        model.Add(sum(bool_sub_job_se) < len(bool_sub_job_se)).OnlyEnforceIf(j_b_se.Not())
        total_C_se_list.append(C_se_list)
        bool_sub_job_se_list.append(bool_sub_job_se)
        job_p_se_list.append(job_p_se_sub)

    for x in range(len(t_t_list)):
        x_s = model.NewConstant(int(t_t_list[x] - 48))
        ii = model.NewConstant(48)
        x_e = model.NewConstant(t_t_list[x])
        y_s = model.NewConstant(0)
        iii = model.NewConstant(8)
        y_e = model.NewConstant(8)
        x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % x)
        y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % x)
        x_intervals.append(x_ii)
        y_intervals.append(y_ii)

    for i in range(len(job_data_se)):
        total_interval_se = 0
        x_t_intervals_se = []
        for j in range(len(job_data_se[i])):
            for k in range(len(total_C_se_list[i][j])):
                total_interval_se += total_C_se_list[i][j][k] * V_j[2]
            t_ii = model.NewIntVar(1, 999999, 't_ii_%d' % j)
            model.Add(t_ii == total_interval_se + 1)
            I_se = model.NewIntVar(0, 999999, 'In_%d' % j)
            model.AddDivisionEquality(I_se, job_data_se[i][j], t_ii)
            j_sub_p_I_se_intervals = model.NewOptionalIntervalVar(job_p_se_list[i][j][0], I_se + 30,
                                                                  job_p_se_list[i][j][2], bool_sub_job_se_list[i][j],
                                                                  '%d_%d_I' % (i, j))
            x_t_intervals_se.append(j_sub_p_I_se_intervals)
            # de.append(int(3))
            y_end = model.NewIntVar(0, 10, 'y_end_%d%d%d' % (i, j, 8))
            j_sub_p_se_intervals = model.NewOptionalIntervalVar(job_p_se_list[i][j][0], I_se + 1,
                                                                job_p_se_list[i][j][1], total_C_se_list[i][j][0],
                                                                'p_%d_%d' % (i, j))
            j_sub_c_se_intervals = model.NewOptionalIntervalVar(8, 1, y_end, total_C_se_list[i][j][0],
                                                                'c_%d_%d' % (i, j))
            x_intervals.append(j_sub_p_se_intervals)
            y_intervals.append(j_sub_c_se_intervals)

            # for m in range(len(total_C_list[i][j])):  #     y_end = model.NewIntVar(1, 7, 'y_end_%d%d%d' % (i, j, m))  #     j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][0], I + 1, job_p_list[i][j][1],  #                                                      total_C_list[i][j][m], 'p_%d_%d' % (i, j))  #     j_sub_c_intervals = model.NewOptionalIntervalVar(m, 1, y_end,  #                                                      total_C_list[i][j][m], 'c_%d_%d' % (i, j))  #     x_intervals.append(j_sub_p_intervals)  #     y_intervals.append(j_sub_c_intervals)

        model.AddNoOverlap(x_t_intervals_se)
    model.AddNoOverlap2D(x_intervals, y_intervals)

    model.Maximize(total_bb)
    solver = cp_model.CpSolver()
    solver.parameters.num_search_workers = 8
    solver.parameters.max_time_in_seconds = t
    # solver.parameters.log_search_progress = True
    status = solver.Solve(model)

    if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
        print("status: ", status)

        for i in range(len(job_data_se)):
            solu_x_sub_se = []
            for j in range(len(job_data_se[i])):
                solution_x_se = []
                solution_x_se.append(solver.Value(job_p_se_list[i][j][0]))
                solution_x_se.append(solver.Value(job_p_se_list[i][j][1]))
                solu_x_sub_se.append(solution_x_se)
            solution_x_total.append(solu_x_sub_se)

        for i in range(len(job_data_se)):
            solu_bool_sub_se = []
            for j in range(len(job_data_se[i])):
                solu_bool_sub_se.append(solver.Value(bool_sub_job_se_list[i][j]))
            solution_bool_sub_job.append(solu_bool_sub_se)

        for i in range(len(job_data_se)):
            solu_C_se_sub = []
            for j in range(len(job_data_se[i])):
                solu_C_sub_sub_se = []
                for k in range(len(total_C_se_list[i][j])):
                    solu_C_sub_sub_se.append(solver.Value(total_C_se_list[i][j][k]))
                solu_C_se_sub.append(solu_C_sub_sub_se)
            solution_bool_C.append(solu_C_se_sub)

        print("youjie")
    else:
        print('No solution found.')

    return solution_x_total, solution_bool_sub_job, solution_bool_C


def solve(job_data, job_data_se, d_list, d_list_se, data_start_se, job_type, sxt, sbsj, sbc, t):
    """
    该函数用于求解，输入输出参数解释如下
    :param job_data:任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量,同时任务的优先级默认从高到低依次排列
    :param job_type:货物形态
    :param se:是否为自制
    :param d:任务的截止时间
    :param t:求解时间，若最后无解，则需调大时间
    :return: solution_x_total 所有子任务的开始处理时间和处理结束时间，单位为分钟
    solution_bool_sub_job 该项对应某一个子任务是否被处理，若为1则被处理，若为0则没被处理
    solution_bool_C 该项对应子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用
    """

    V_j = [2, 17, 3]
    t_t_list = [i * 2 * 60 for i in range(5, 13)]
    total_C_list = []
    total_C_se_list = []
    bool_job_list = []
    bool_job_se_list = []
    bool_sub_job_list = []
    bool_sub_job_se_list = []
    job_p_list = []
    job_p_se_list = []
    x_intervals = []
    y_intervals = []
    solution_x_total = []
    solution_bool_sub_job = []
    solution_bool_C = []
    de = []
    rs_c = []
    total_b = 0
    total_bb = 0

    model = cp_model.CpModel()
    max_time = cp_model.INT32_MAX
    print("job_data: ", job_data)
    # print("d: ", d)

    for i in range(len(job_data)):
        j_b = model.NewBoolVar('%d' % i)
        total_bb += j_b
        bool_job_list.append(j_b)
        job_p_sub = []
        C_list = []
        bool_sub_job = []
        for j in range(len(job_data[i])):
            j_sub_b = model.NewBoolVar('%d_%d' % (i, j))
            bool_sub_job.append(j_sub_b)
            total_b += j_sub_b
            sub_c_list = []
            sub_p_list = []
            j_sub_p_s = model.NewIntVar(480, 1441, 'p_s_%d_%d' % (i, j))
            j_sub_p_e = model.NewIntVar(480, 1441, 'p_e_%d_%d' % (i, j))
            j_sub_p_e_1 = model.NewIntVar(480, 1441, 'p_e1_%d_%d' % (i, j))
            due_data_d = model.NewBoolVar('due_data_d')
            c_d = model.NewBoolVar('c_d')
            model.Add(j_sub_p_e <= d_list[i]).OnlyEnforceIf(due_data_d)
            model.Add(j_sub_p_e > d_list[i]).OnlyEnforceIf(due_data_d.Not())
            sub_p_list.append(j_sub_p_s)
            sub_p_list.append(j_sub_p_e)
            sub_p_list.append(j_sub_p_e_1)
            job_p_sub.append(sub_p_list)
            # if se[i]:
            #     for m in range(7):
            #         b = model.NewBoolVar('%d_%d_%d' % (i, j, m))
            #         sub_c_list.append(b)
            # else:
            if job_type[i][j] == 0:
                b = model.NewBoolVar('%d_%d_%d' % (i, j, 7))
                sub_c_list.append(b)
            else:
                for m in range(6):
                    b = model.NewBoolVar('%d_%d_%d' % (i, j, m))
                    sub_c_list.append(b)

            model.Add(sum(sub_c_list) > 0).OnlyEnforceIf(c_d)
            model.Add(sum(sub_c_list) == 0).OnlyEnforceIf(c_d.Not())
            model.Add(due_data_d == 1).OnlyEnforceIf(c_d)
            model.Add(c_d + due_data_d == 2).OnlyEnforceIf(j_sub_b)
            model.Add(c_d + due_data_d < 2).OnlyEnforceIf(j_sub_b.Not())
            C_list.append(sub_c_list)
        model.Add(sum(bool_sub_job) == len(bool_sub_job)).OnlyEnforceIf(j_b)
        model.Add(sum(bool_sub_job) < len(bool_sub_job)).OnlyEnforceIf(j_b.Not())
        total_C_list.append(C_list)
        bool_sub_job_list.append(bool_sub_job)
        job_p_list.append(job_p_sub)

    for x in range(len(t_t_list)):
        x_s = model.NewConstant(int(t_t_list[x] - 48))
        ii = model.NewConstant(48)
        x_e = model.NewConstant(t_t_list[x])
        y_s = model.NewConstant(0)
        iii = model.NewConstant(7)
        y_e = model.NewConstant(7)
        x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % x)
        y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % x)
        x_intervals.append(x_ii)
        y_intervals.append(y_ii)

    for g in range(len(sxt)):
        for i in range(len(sxt[g])):
            x_s = model.NewConstant(sxt[g][i][0])
            ii = model.NewConstant(sxt[g][i][1] - sxt[g][i][0])
            x_e = model.NewConstant(sxt[g][i][1])
            y_s = model.NewConstant(7)
            iii = model.NewConstant(1)
            y_e = model.NewConstant(8)
            # print("sbsj[g][i]: ", sbsj[g][i])
            if sbsj[g][i] == 1:
                x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, sbsj[g][i], 'x_ii%d' % i)
                y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, sbsj[g][i], 'y_ii%d' % i)
                x_intervals.append(x_ii)
                y_intervals.append(y_ii)
                de.append(int(3))
                rs_c.append(x_ii)

    for i in range(len(job_data)):
        total_interval = 0
        x_t_intervals = []
        for j in range(len(job_data[i])):
            for k in range(len(total_C_list[i][j])):
                total_interval += total_C_list[i][j][k] * V_j[job_type[i][j]]
            t_i = model.NewIntVar(1, 999999, 't_i_%d' % j)
            model.Add(t_i == total_interval + 1)
            I = model.NewIntVar(0, 999999, 'In_%d' % j)
            model.AddDivisionEquality(I, job_data[i][j], t_i)
            j_sub_p_I_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][0], I + 30, job_p_list[i][j][2],
                                                               bool_sub_job_list[i][j], '%d_%d_I' % (i, j))
            x_t_intervals.append(j_sub_p_I_intervals)
            for m in range(len(total_C_list[i][j])):
                # de.append(int(17))
                y_end = model.NewIntVar(1, 6, 'y_end_%d%d%d' % (i, j, m))
                j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][0], I + 1, job_p_list[i][j][1],
                                                                 total_C_list[i][j][m], 'p_%d_%d' % (i, j))
                j_sub_c_intervals = model.NewOptionalIntervalVar(m, 1, y_end, total_C_list[i][j][m], 'c_%d_%d' % (i, j))
                if job_type[i][j] == 1:
                    rs_c.append(j_sub_p_intervals)
                    de.append(int(17))
                x_intervals.append(j_sub_p_intervals)
                y_intervals.append(j_sub_c_intervals)

        model.AddNoOverlap(x_t_intervals)

    model.AddNoOverlap2D(x_intervals, y_intervals)
    model.AddCumulative(rs_c, de, 84)

    for i in range(len(job_data) - 1):
        model.Add(bool_job_list[i] == 1).OnlyEnforceIf(bool_job_list[i + 1])

    model.Maximize(total_bb)
    solver = cp_model.CpSolver()
    solver.parameters.num_search_workers = 8
    solver.parameters.max_time_in_seconds = t
    # solver.parameters.log_search_progress = True
    status = solver.Solve(model)

    if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
        print("status: ", status)
        for i in range(len(job_data)):
            solu_x_sub = []
            for j in range(len(job_data[i])):
                solution_x = []
                solution_x.append(solver.Value(job_p_list[i][j][0]))
                solution_x.append(solver.Value(job_p_list[i][j][1]))
                solu_x_sub.append(solution_x)
            solution_x_total.append(solu_x_sub)

        solution_x_total = solution_x_total + sxt

        for i in range(len(job_data)):
            solu_bool_sub = []
            for j in range(len(job_data[i])):
                solu_bool_sub.append(solver.Value(bool_sub_job_list[i][j]))
            solution_bool_sub_job.append(solu_bool_sub)

        solution_bool_sub_job = solution_bool_sub_job + sbsj

        for i in range(len(job_data)):
            solu_C_sub = []
            for j in range(len(job_data[i])):
                solu_C_sub_sub = []
                for k in range(len(total_C_list[i][j])):
                    solu_C_sub_sub.append(solver.Value(total_C_list[i][j][k]))
                solu_C_sub.append(solu_C_sub_sub)
            solution_bool_C.append(solu_C_sub)

        solution_bool_C = solution_bool_C + sbc

        print("youjie")
    else:
        print('No solution found.')

    return solution_x_total, solution_bool_sub_job, solution_bool_C


def plot_graph(job_data, job_data_se, solution_x_total, solution_bool_sub_job, solution_bool_C):
    import matplotlib.pyplot as plt

    colors = []
    for i in range(len(job_data) + len(job_data_se)):
        colors.append(f'#%06x' % random.randint(0, 0xFFFFFF))

    fig, ax = plt.subplots()

    for i in range(len(solution_bool_C)):
        if i < len(job_data):
            for j in range(len(solution_bool_C[i])):
                for k in range(len(solution_bool_C[i][j])):
                    color = colors[i]
                    if solution_bool_sub_job[i][j] and solution_bool_C[i][j][k]:
                        if len(solution_bool_C[i][j]) == 1:
                            rectangle = plt.Rectangle((solution_x_total[i][j][0] / 60, 6),
                                                      (solution_x_total[i][j][1] - solution_x_total[i][j][0]) / 60, 1,
                                                      facecolor=color)
                            rectangle.set_edgecolor('black')
                            rectangle.set_linewidth(1.5)
                            ax.add_patch(rectangle)
                        else:
                            rectangle = plt.Rectangle((solution_x_total[i][j][0] / 60, k),
                                                      (solution_x_total[i][j][1] - solution_x_total[i][j][0]) / 60, 1,
                                                      facecolor=color)
                            rectangle.set_edgecolor('black')
                            rectangle.set_linewidth(1.5)
                            ax.add_patch(rectangle)

        else:
            for j in range(len(solution_bool_C[i])):
                for k in range(len(solution_bool_C[i][j])):
                    color = colors[i]
                    if solution_bool_sub_job[i][j] and solution_bool_C[i][j][k]:
                        rectangle = plt.Rectangle((solution_x_total[i][j][0] / 60, 7),
                                                  (solution_x_total[i][j][1] - solution_x_total[i][j][0]) / 60, 1,
                                                  facecolor=color)
                        rectangle.set_edgecolor('black')
                        rectangle.set_linewidth(1.5)
                        ax.add_patch(rectangle)

    for x in [i * 2 for i in range(1, 13)]:
        ax.axvline(x, color='red', linestyle='--', linewidth=1)

    # ax.axvline(13, color='red', linestyle='--', linewidth=1)
    #
    # ax.axvline(19, color='red', linestyle='--', linewidth=1)

    ax.set_xlim(0, 25)
    ax.set_ylim(0, 10)

    ax.set_xlabel('Time (hours)')
    ax.set_ylabel('channel')
    ax.set_title('Time window')

    plt.show()


if __name__ == '__main__':
    t1 = time.time()
    V_j = [2, 17, 3]
    data_end, data_end_se, job_type, d_list, d_list_se, data_start_se = generate_data(30, 4, 8)
    print("data_end: ", data_end)
    print("data_end_se: ", data_end_se)
    print("job_type: ", job_type)
    print("d_list: ", d_list)
    print("d_list_se: ", d_list_se)
    print("data_start_se: ", data_start_se)
    sxt, sbsj, sbc = se_solve(data_end_se, d_list_se, data_start_se, 30.0)
    print("sxt: ", sxt)
    print("sbsj: ", sbsj)
    print("sbc: ", sbc)
    solution_x_total, solution_bool_sub_job, solution_bool_C = solve(data_end, data_end_se, d_list, d_list_se,
                                                                     data_start_se, job_type, sxt, sbsj, sbc, 30.0)
    print("solution_x_total: ", solution_x_total)
    print("solution_bool_sub_job: ", solution_bool_sub_job)
    print("solution_bool_C: ", solution_bool_C)
    t2 = time.time()
    print("t: ", t2 - t1)
    # plot_graph(data_end, data_end_se, solution_x_total, solution_bool_sub_job, solution_bool_C)
    # ini_solution_x_total, ini_solution_bool_sub_job, ini_solution_bool_C, ini_job_re, under_process = get_re_t(solution_x_total, solution_bool_sub_job, solution_bool_C, 720)
    # print("ini_solution_x_total: ", ini_solution_x_total)
    # print("ini_solution_bool_sub_job: ", ini_solution_bool_sub_job)
    # print("ini_solution_bool_C: ", ini_solution_bool_C)
    # print("ini_job_re: ", ini_job_re)
    # print("under_process: ", under_process)

    in_job, in_job_se, in_job_type, in_d_list, in_d_list_se, data_start_se = generate_data_1(20, 4, 8)
    print("in_job: ", in_job)
    print("in_job_se: ", in_job_se)
    print("in_job_type: ", in_job_type)
    print("in_d_list: ", in_d_list)
    print("in_d_list_se: ", in_d_list_se)
    print("data_start_se: ", data_start_se)
    s_solution_x_total, s_solution_bool_sub_job, s_solution_bool_C = insert_fun(in_job, in_job_type, in_job_se,
                                                                                in_d_list_se, len(data_end),
                                                                                solution_x_total, solution_bool_sub_job,
                                                                                solution_bool_C, 720, in_d_list, d_list,
                                                                                job_type, data_end, V_j, 60.0)
    print("s_solution_x_total: ", s_solution_x_total)
    print("s_solution_bool_sub_job: ", s_solution_bool_sub_job)
    print("s_solution_bool_C: ", s_solution_bool_C)
